//
//  TcpServer.swift
//  pluto
//
//  Created by andyge on 15/7/26.
//  Copyright © 2015年 gejingguo. All rights reserved.
//

import Foundation


public class TcpServer: PollObject {
    public var fd: Int32? = nil
    public var id: Int = 0
    var ip: String = ""
    var port: Int = 0
    
    public init(ip: String, port: Int) {
        self.ip = ip
        self.port = port
        print("tcpserver ip:\(self.ip) port:\(self.port) create.")
    }
    
    deinit {
        if fd != nil {
            Darwin.close(fd!)
            fd = nil
        }
        print("tcpserver id:\(self.id) deinit.")
    }
    
    // 监听
    public func listen() -> Error? {
        //let err: Error? = nil
        //print("ip:\(self.ip), port:\(self.port) listening...")
        if fd >= 0 {
            //return TcpError(err: TcpErrorNo.TcpErrorNo_SocketGetOption.rawValue, msg: "")
            close(fd!)
            fd = nil
        }
        
        fd = socket(AF_INET, SOCK_STREAM, 0)
        if fd < 0 {
            return TcpError(err: TcpErrorNo.TcpErrorNo_CreateSocket.rawValue)
        }
        
        let err = setSocketReuseAddr(fd!)
        if err != nil {
            
            return err
        }
        
        var addr = sockaddr_in()
        addr.sin_family = sa_family_t(AF_INET)
        addr.sin_port = in_port_t(htons(CUnsignedShort(port)))
        var buf = INADDR_NONE
        ip.withCString{ cs in inet_pton(AF_INET, cs, &buf) }
        addr.sin_addr.s_addr = in_addr_t(buf)
        
        var ret = withUnsafePointer(&addr){ ptr -> Int32 in
            let bptr = UnsafePointer<sockaddr>(ptr)
            return bind(fd!, bptr, socklen_t(sizeof(sockaddr_in)))
        }
        
        if ret != 0 {
            return TcpError(err: TcpErrorNo.TcpErrorNo_SocketBind.rawValue)
        }
        
        ret = Darwin.listen(fd!, 5)
        if ret != 0 {
            return TcpError(err: TcpErrorNo.TcpErrorNo_SocketListen.rawValue)
        }
        
        print("tcpserver listen ok, \(self)")
        
        return nil
        //return 0;
    }
    
    // 接受新连接
    func accept() -> (err: Error?, clientFd: Int32?, strAddr: String?) {
        if fd == nil {
            return (TcpError(err: TcpErrorNo.TcpErrorNo_SocketFdInvalid.rawValue), nil, nil)
        }
        
        var remoteAddr = sockaddr_in()
        var remoteAddrLen = socklen_t(Int(sizeof(sockaddr_in)))
        
        let newFd = withUnsafeMutablePointer(&remoteAddr) {
            ptr -> Int32 in
            let bptr = UnsafeMutablePointer<sockaddr>(ptr) // cast
            //print("accept fd:\(fd!)")
            return Darwin.accept(fd!, bptr, &remoteAddrLen);// buflenptr)
        }
        //let newFd = Darwin.accept(fd!, remoteAddr, socklen_t_cast(&remoteAddrLen))
        //Darwin.accept(<#T##Int32#>, <#T##UnsafeMutablePointer<sockaddr>#>, <#T##UnsafeMutablePointer<socklen_t>#>)
        print("accept newFd:\(newFd), \(remoteAddr), \(remoteAddrLen)")
        
        if newFd < 0 {
            if errno == EWOULDBLOCK || errno == EAGAIN {
                //return (TcpError(err: TcpErrorNo.TcpErrorNo_SocketEagain.rawValue), nil)
                return (nil, nil, nil)
            }
            return (TcpError(err: TcpErrorNo.TcpErrorNo_SocketAccept.rawValue), nil, nil)
        }
        
        let len   = Int(INET_ADDRSTRLEN) + 2
        var buf   = [CChar](count: len, repeatedValue: 0)
        
        // 转化字符串地址
        let cs = inet_ntop(AF_INET, &remoteAddr.sin_addr, &buf, socklen_t(len))
        //inet_ntop(<#T##Int32#>, <#T##UnsafePointer<Void>#>, <#T##UnsafeMutablePointer<Int8>#>, <#T##socklen_t#>)
        
        print("tcpserver accept new conn, fd:\(newFd)")
        return (nil, newFd, String.fromCString(cs))
    }
    
    public func onRead(poller: Poller) -> Error? {
        //if poller.tcpDelegate != nil {
        //    poller.tcpDelegate!.onTcpServerRead(self, poller: poller)
        //}
        var (err, newFd, saddr) = self.accept()
        if err != nil {
            return err
        }
        
        var tcpClient: PollObject = TcpClient(poller: poller, fd: newFd!, serverAddr: saddr!, server: self)
        err = poller.addPollObject(&tcpClient)
        if err != nil {
            // 这里不能返回err, 否则poller会吧tcpserver删掉
            // 通知外部代理接口
            poller.tcpDelegate!.onTcpClinetAddError(self, poller: poller, err: err!)
            return nil
        }
        
        return nil
    }
    
    public func onWrite(poller: Poller) -> Error? {
        print("tcpserver onwrite.")
        return nil
    }
    
    public func onError(poller: Poller, err: Error) {
        
        poller.tcpDelegate?.onTcpServerError(self, err: err)
    }
}

